package com.nulldev.util.data.FastMath.impls;

import com.nulldev.util.data.FastMath.Math;

public class Rivens extends Math {

	public static final Rivens INSTANCE = new Rivens();

	private static final int BF_SIN_BITS;
	private static final int BF_SIN_MASK;
	private static final int BF_SIN_COUNT;
	private static final float BF_radFull;
	private static final float BF_radToIndex;
	private static final float BF_degFull;
	private static final float BF_degToIndex;
	private static final float[] BF_sin;
	private static final float[] BF_cos;

	public static float sin(final float rad) {
		return BF_sin[(int) (rad * BF_radToIndex) & BF_SIN_MASK];
	}

	public static double sin(final double rad) {
		return BF_sin[(int) (rad * BF_radToIndex) & BF_SIN_MASK];
	}

	public static float cos(final float rad) {
		return BF_cos[(int) (rad * BF_radToIndex) & BF_SIN_MASK];
	}

	public static double cos(final double rad) {
		return BF_cos[(int) (rad * BF_radToIndex) & BF_SIN_MASK];
	}

	static {
		BF_SIN_BITS = 12;
		BF_SIN_MASK = ~(-1 << BF_SIN_BITS);
		BF_SIN_COUNT = BF_SIN_MASK + 1;
		BF_radFull = 6.2831855f;
		BF_degFull = 360.0f;
		BF_radToIndex = BF_SIN_COUNT / BF_radFull;
		BF_degToIndex = BF_SIN_COUNT / BF_degFull;
		BF_sin = new float[BF_SIN_COUNT];
		BF_cos = new float[BF_SIN_COUNT];
		for (int i = 0; i < BF_SIN_COUNT; ++i) {
			BF_sin[i] = (float) Math.sin((i + 0.5f) / BF_SIN_COUNT * BF_radFull);
			BF_cos[i] = (float) Math.cos((i + 0.5f) / BF_SIN_COUNT * BF_radFull);
		}
		for (int i = 0; i < 360; i += 90) {
			BF_sin[(int) (i * BF_degToIndex) & BF_SIN_MASK] = (float) Math.sin(i * 3.141592653589793 / 180.0);
			BF_cos[(int) (i * BF_degToIndex) & BF_SIN_MASK] = (float) Math.cos(i * 3.141592653589793 / 180.0);
		}
	}
}
